﻿using System;
using System.Collections.Generic;
using System.Text;
using Pixysoft.Framework.Verifications;
using System.Reflection;
using Pixysoft.Framework.Reflection.Controller;
using Pixysoft.Tools;

namespace Pixysoft.Framework.Reflection
{
    class BeanMap : IBeanMap
    {
        private Type targetType = null;

        private object target = null;

        private BeanMapFactory.GetBeanHandler getHandler;

        private BeanMapFactory.SetBeanHandler setHandler;

        Dictionary<string, object> beans = new Dictionary<string, object>();

        public BeanMap(object target, Type targetType, BeanMapFactory.GetBeanHandler getHandler, BeanMapFactory.SetBeanHandler setHandler)
        {
            this.target = target;

            this.targetType = targetType;

            this.setHandler = setHandler;

            this.getHandler = getHandler;

            this.getHandler(this.target, this);
        }

        public bool ContainsKey(string key)
        {
            if (string.IsNullOrEmpty(key))
                throw Exceptions.VerificationFailedException(key);

            key = key.Trim().ToUpper();

            return beans.ContainsKey(key);
        }

        public string[] Keys
        {
            get
            {
                List<string> list = new List<string>();

                foreach (string key in beans.Keys)
                {
                    list.Add(key);
                }

                return list.ToArray();
            }
        }

        public object GetBean()
        {
            setHandler(target, this);

            return target;
        }

        public T GetBean<T>()
        {
            return (T)GetBean();
        }

        public T Clone<T>()
        {
            Type tType = typeof(T);

            object clone = null;

            if (tType.IsInterface)
            {
                clone = ReflectionManager.CreatePojo<T>();
            }
            else
            {
                clone = tType.GetConstructor(Type.EmptyTypes).Invoke(new object[] { });
            }

            IBeanMap cloneMap = ReflectionManager.CreateBeanMap(clone);

            foreach (string key in beans.Keys)
            {
                if (cloneMap.ContainsKey(key))
                    cloneMap.SetValue(key, beans[key]);
            }

            return cloneMap.GetBean<T>();
        }

        public bool HasValue(string key)
        {
            if (string.IsNullOrEmpty(key))
                throw Exceptions.VerificationFailedException(key);

            key = key.Trim().ToUpper();

            return beans.ContainsKey(key);
        }

        public bool RemoveValue(string key)
        {
            if (string.IsNullOrEmpty(key))
                throw Exceptions.VerificationFailedException(key);

            key = key.Trim().ToUpper();

            if (!beans.ContainsKey(key))
                return false;

            object formerValue = beans[key];

            if (formerValue == null)
                beans[key] = null;
            else
                beans[key] = ParserHelper.GetNullValue(formerValue.GetType());

            return true;
        }

        public object GetValue(string key)
        {
            if (string.IsNullOrEmpty(key))
                throw Exceptions.VerificationFailedException(key);

            key = key.Trim().ToUpper();

            if (beans.ContainsKey(key))
                return beans[key];

            throw Exceptions.UnexpectedResultException("Missing key:{0} for target:{1}", key, this.targetType.Name);
        }

        public object TryGetValue(string key, Type type)
        {
            if (string.IsNullOrEmpty(key))
                throw Exceptions.VerificationFailedException(key);

            key = key.Trim().ToUpper();

            object returnValue = null;

            if (beans.ContainsKey(key))
                returnValue = beans[key];
            else
                return ParserHelper.GetNullValue(type);

            if (returnValue == null || returnValue == DBNull.Value)
                return ParserHelper.GetNullValue(type);

            object parseValue = null;

            if (!ParserHelper.TryParse(type, returnValue, out parseValue, null))
                throw Exceptions.UnexpectedResultException("TRYGETVALUE:set bean and return object fail. object:{0} key:{1} type:{2}", targetType.Name, key, type.Name);

            return parseValue;
        }

        public void SetValue(string key, object value)
        {
            if (string.IsNullOrEmpty(key))
                throw Exceptions.VerificationFailedException(key);

            key = key.Trim().ToUpper();

            if (beans.ContainsKey(key))
                beans[key] = value;
            else
                beans.Add(key, value);
        }

        public int Count
        {
            get
            {
                return beans.Count;
            }
        }

        public void Dispose()
        {
            this.setHandler = null;
            this.getHandler = null;
            this.target = null;
            this.targetType = null;
            this.beans.Clear();
        }
    }
}
